﻿/******************************************************************************
 * GWebSearch.cs
 * 
 * This module implements the GWebSearch base search class and related types.
 *  
 * Date:   12/2008
 * 
 * Copyright (c) 2009, Mark Betz 
 * 
 * All rights reserved. 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met: 
 * 
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer. 
 *   * Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer in the 
 *     documentation and/or other materials provided with the distribution. 
 *   * Neither the name of the Author nor the names of contributors may be 
 *     used to endorse or promote products derived from this software
 *     without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY MARK BETZ ''AS IS'' AND ANY  EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL MARK BETZ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 * 
 */
using System;

namespace GSearch
{
    /// <summary>
    /// Type of the event arguments to GWebSearch events
    /// </summary>
    public class WebSearchEventArgs : SearchEventArgs
    {
        /// <summary>
        /// Constructor used to initialize from a SearchEventArgs object.
        /// </summary>
        /// <param name="se"></param>
        public WebSearchEventArgs(SearchEventArgs se)
            : base(se.Status, se.Result, se.Ex)
        {
        }

        /// <summary>
        /// Returns a reference to a <see cref="GSearch.GWebResponse"/> object
        /// for certain types of events. Null for all others.
        /// </summary>
        public new GWebResponse Result 
        { get { return (GWebResponse)(base.Result); } }
    }
    
    /// <summary>
    /// WebSearchArgs derives from <see cref="GSearch.SearchArgs"/> and implements
    /// web search-specific arguments.
    /// <example>
    /// The following code illustrates how to create and use the WebSearchArgs class:
    /// <code>
    /// GWebSearch gws = new GWebSearch();
    /// WebSearchArgs wsa = new WebSearchArgs();
    /// wsa.Terms = "C# guru blog";
    /// GWebResponse resp = gws.Search(wsa);
    /// </code>
    /// </example>
    /// </summary>
    public class WebSearchArgs : SearchArgs
    {
        /// <summary>
        /// Default constructor for the WebSearchArgs class.
        /// </summary>
        public WebSearchArgs()
        {
            CustomSearchId = "";
            CustomSearchUrl = "";
            Filter = SearchSafety.Full;
            ResultLang = SearchResultLang.All;
        }

        /// <summary>
        /// ToQueryString overrides the base class version. It calls the
        /// base class version to get the root of the query string, and then
        /// builds the rest of the parameters.
        /// </summary>
        /// <returns></returns>
        public override string ToQueryString()
        {
            string qry = base.ToQueryString();

            // cx= unique id of custom search engine to use for this query
            if ( "" != CustomSearchId )
                qry += "&cx=" + CustomSearchId;
                
            // cref= url of custom search engine
            if ( "" != CustomSearchUrl )
                qry += "&cref=" + Uri.EscapeUriString(CustomSearchUrl);
                
            // safe= level of offensive image screening
            qry += "&safe=" + ArgStrings.sfmap[Convert.ToInt32(Filter)];
            
            // lr= the language results should be returned in
            if ( SearchResultLang.All != ResultLang )
                qry += "&lr=" + ArgStrings.lrmap[Convert.ToInt32(ResultLang)];

            return qry;
        }

        /// <summary>
        /// A System.String identifying the ID of a custom search engine to use
        /// for the query.
        /// </summary>
        public string CustomSearchId { get; set; }
        
        /// <summary>
        /// A System.String containg the URL address of the custom search engine
        /// to use for the query.
        /// </summary>
        public string CustomSearchUrl { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchSafety"/> enum identifying
        /// the level of safe search filtering desired for the query. Full is
        /// the highest level of filtering; Off is the lowest.
        /// </summary>
        public SearchSafety Filter { get; set; }
        
        /// <summary>
        /// A value from the <see cref="GSearch.SearchResultLang"/> enum
        /// identifying the number of results desired. A value of Small will
        /// produce 4 results per page; a value of Large will produce 8
        /// results per page. In both cases a total of 8 pages will be sent.
        /// </summary>
        public SearchResultLang ResultLang { get; set; }
    }

    /// <summary>
    /// The GWebSearch class provides an interface for searching the Web using Google.
    /// It derives from <see cref="GSearch.GSearchCore"/> which does a large part of
    /// the work.
    /// <example>
    /// The following example shows how to use the GWebSearch class to search the web
    /// using Google:
    /// <code>
    /// GWebSearch gws = new GWebSearch();
    /// WebSearchArgs wsa = new WebSearchArgs();
    /// wsa.Terms = "C# guru blog";
    /// GWebResponse resp = gws.Search(wsa);
    /// if ( resp.Response.Results.Length > 0 )
    ///     // process results
    /// </code>
    /// </example>
    /// </summary>
    public class GWebSearch : GSearchCore
    {
#if (!SILVERLIGHT)
        /// <summary>
        /// Performs a syncronous search for web pages using the supplied arguments. The
        /// calling thread blocks until results are returned or an exception is thrown.
        /// This method is not available in the Silverlight version of the libraries.
        /// </summary>
        /// <param name="args"><see cref="GSearch.WebSearchArgs"/> containing the search arguments</param>
        /// <returns><see cref="GSearch.GWebResponse"/> containing the results, if any</returns>
        /// <exception cref="Exception">if an error occurs during the search</exception>
        public GWebResponse Search(WebSearchArgs args)
        {
            return (GWebResponse)base.Search(args);
        }
#endif

        /// <summary>
        /// Peforms an asyncronous search for web pages using the supplied arguments. The
        /// calling thread returns immediately, and results or errors are indicated by
        /// raising the SearchFailed, SearchComplete, or SearchProgressChanged events.
        /// Results are returned on the UI thread.
        /// </summary>
        /// <param name="args"><see cref="GSearch.WebSearchArgs"/> containing the search arguments</param>
        /// <exception cref="Exception">if an error occurs during the search</exception>
        public void SearchAsync(WebSearchArgs args)
        {
            base.SearchAsync(args);
        }

        /// <summary>
        /// This event is raised when the search is complete and the results are ready
        /// to be returned to the client.
        /// </summary>
        public event EventHandler<WebSearchEventArgs> SearchComplete;

        /// <summary>
        /// This event is raised when the search fails for some reason. The event
        /// arguments Ex property will reference the exception.
        /// </summary>
        public event EventHandler<WebSearchEventArgs> SearchFailed;

        /// <summary>
        /// This event is raised when key steps in the search process are completed.
        /// See the <see cref="GSearch.SearchStatus"/> enumeration for possible values for the
        /// WebSearchEventArgs.Status parameter.
        /// <seealso cref="GSearch.SearchStatus"/>
        /// </summary>
        public event EventHandler<WebSearchEventArgs> SearchProgressChanged;

        /// <summary>
        /// Returns a System.String containing a complete uri for the web search
        /// service
        /// </summary>
        public override string ServiceURI
        {
            get { return base.ServiceURI + WebResources.ServiceURI; }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchComplete event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchComplete(SearchEventArgs e)
        {
            EventHandler<WebSearchEventArgs> ev = SearchComplete;
            if (null != ev)
            {
                WebSearchEventArgs ie = new WebSearchEventArgs(e);
                ev(this, ie);
            }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchFailed event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchFailed(SearchEventArgs e)
        {
            EventHandler<WebSearchEventArgs> ev = SearchFailed;
            if (null != ev)
            {
                WebSearchEventArgs ie = new WebSearchEventArgs(e);
                ev(this, ie);
            }
        }

        /// <summary>
        /// Called by GSearchCore to raise the SearchProgressChanged event
        /// </summary>
        /// <param name="e"><see cref="SearchEventArgs"/> containing 
        /// information about the event</param>
        protected override void OnSearchProgressChanged(SearchEventArgs e)
        {
            EventHandler<WebSearchEventArgs> ev = SearchProgressChanged;
            if (null != ev)
            {
                WebSearchEventArgs ie = new WebSearchEventArgs(e);
                ev(this, ie);
            }
        }

        /// <summary>
        /// Deserialize is called from the base when the search returns a valid
        /// result stream, it refers the call to the base class DeserializeImpl
        /// which actually does the work of deserialization.
        /// </summary>
        /// <param name="result">Stream result passed from the base class</param>
        /// <returns>Instance of <see cref="GSearch.GWebResponse"/> as GResponse</returns>
        protected override GResponse Deserialize(System.IO.Stream result)
        {
            return DeserializeImpl<GWebResponse>(result);
        } 
    }
}
